package com.jzsec.proxy.jzsecproxy.config;

import lombok.extern.slf4j.Slf4j;
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.scheduling.annotation.AsyncConfigurer;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import javax.annotation.PostConstruct;
import java.lang.reflect.Method;
import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * @desc 定义异步线程池，并交由Spring调度
 * @question 拒绝策略、线程池大小配置
 * @answer 1、 拒绝策略 - CallerRunsPolicy 饱和策略；2、使用计算公式计算线程池大小，如果配置文件指定，则使用配置文件
 */
@Configuration
@EnableAsync
@Slf4j
public class AsyncTaskExecutorConfiguration implements AsyncConfigurer {

	private Integer corePoolSize = 100;
	private Integer queueCapacity = 0;
	private Integer maxPoolSize = 1000;

	@Autowired
	private Environment env;
	@PostConstruct
	private void init() {
		corePoolSize = new Double(Runtime.getRuntime().availableProcessors() * 0.8 * (1 + 30)).intValue();   // w/c 在开发环境为30
		maxPoolSize = new Double(corePoolSize / 0.8).intValue(); // cpu 全部利用，但是 还要考虑内存、文件描述符、socket描述符是否够用
		corePoolSize = Integer.valueOf(env.getProperty("consumer.executor.core.size", corePoolSize.toString()));
		queueCapacity = Integer.valueOf(env.getProperty("consumer.executor.queue.capacity", queueCapacity.toString()));
		maxPoolSize = Integer.valueOf(env.getProperty("consumer.executor.max.size", maxPoolSize.toString()));
	}

	/**
	 * @return 定义线程池
	 */
	@Override
	@Bean(name = "diyExecutor")
	public Executor getAsyncExecutor() {
		ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
		taskExecutor.setCorePoolSize(corePoolSize);  // 核心线程数
		taskExecutor.setQueueCapacity(queueCapacity);  // 等待队列最大值；不做缓存，也可以防止进程终止导致的消息丢失问题
		taskExecutor.setMaxPoolSize(maxPoolSize);  // 最大线程数
		taskExecutor.setAllowCoreThreadTimeOut(true);  // 允许核心线程被回收
		taskExecutor.setKeepAliveSeconds(60);  // 一个线程空闲时间达到keepAliveTiime，该线程就退出
		taskExecutor.setWaitForTasksToCompleteOnShutdown(true);  // 等待任务完成后再销毁线程池
		taskExecutor.setAwaitTerminationSeconds(60);  // 最多等待60秒后强制销毁
		taskExecutor.setThreadNamePrefix("diyExecutor-");
		// 当工作线程数达到线程池最大值时，使用“调用者运行策略”来阻塞调用线程，防止更多任务撑爆线程池
		taskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
		// 当工作线程数达到线程池最大值时，使用“中止策略” 终止执行当前任务并抛出异常
//		taskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy());
		// 当工作线程数达到线程池最大值时，使用“抛弃策略”直接抛弃 悄悄地 当前任务
//		taskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardPolicy());
		// 当工作线程数达到线程池最大值时，使用“抛弃最早的策略”直接抛弃 悄悄地 最早的任务
//		taskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardOldestPolicy());
		log.info("corePoolSize = " + taskExecutor.getCorePoolSize()
				+ ", queueCapacity = " + queueCapacity  + ", maxPoolSize = " + taskExecutor.getMaxPoolSize());

		taskExecutor.initialize();  // 初始化
		return taskExecutor;
	}

	@Override
	public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
		return new AsyncUncaughtExceptionHandler() {
			@Override
			public void handleUncaughtException(Throwable throwable, Method method, Object... objects) {
				log.error(method.toString(), throwable);
			}
		};
	}


}
